package vars

import (
	"gitee.com/ymofen/gobase"
	"gitee.com/ymofen/gobase/factory"
	"gitee.com/ymofen/gobase/gotask"
	"gitee.com/ymofen/goplugs/pkg/base"
	"gitee.com/ymofen/supervalue"
	"sync/atomic"
	"time"
)

type PlgVarsLoader struct {
	base.PlgBase

	loadFlag atomic.Int32

	varStartStr, varEndStr           string
	varTokenStartStr, varTokenEndStr string

	from           base.ConfValue
	reloadT        time.Time
	reloadInterval time.Duration
}

func (this *PlgVarsLoader) reloadVars(vars *wrapper.SuperValue) {
	vars.Range(func(key string, val *wrapper.SuperValue) bool {
		v0 := this.parseVars(val.String())
		gobase.RegisterFactoryVar(key, v0)
		this.Log.Debugf("%s=%s", key, v0)
		return true
	})
}

func (this *PlgVarsLoader) reloadFrom() {
	if !this.loadFlag.CompareAndSwap(0, 1) {
		return
	}
	defer this.loadFlag.Store(0)
	if this.from.Valid() {
		buf, err := this.from.GetFrom()
		if err != nil {
			this.Log.Warnf("getfrom err:%s", err.Error())
		}
		str := string(buf)
		str = this.parseVars(str)
		json, err := wrapper.NewSVFromBuf([]byte(str))
		if err != nil {
			this.Log.Warnf("parse err:%s, data:%s", err.Error(), str)
		} else {
			this.reloadVars(json)
		}
	}
}

func (this *PlgVarsLoader) parseVars(txt string) string {
	txt = base.ReplacePlaceholder(txt, this.varStartStr, this.varEndStr, func(key, start, end string) (repl, v string, ok bool) {
		return base.TryGetKeyValue4ReplacePlaceholder(key, start, end, nil)
	})
	if len(this.varTokenStartStr) > 0 && len(this.varTokenEndStr) > 0 {
		txt = gobase.ReplacePlaceholder(txt, this.varTokenStartStr, this.varTokenEndStr, func(key string) (v string, ok bool) {
			return gobase.ParseSimpleExp(key)
		})
	}
	return txt
}

func (this *PlgVarsLoader) ReloadConf(conf *wrapper.SuperValue) error {
	if conf == nil {
		return nil
	}

	this.varStartStr = conf.StringByName("varStart", "$$")
	this.varEndStr = conf.StringByName("varEnd", "$$")

	this.varTokenStartStr = conf.StringByName("varTokenStart", "${")
	this.varTokenEndStr = conf.StringByName("varTokenEnd", "}$")

	this.from = base.ConfValueFrom(conf.StringByName("from", ""))
	this.reloadInterval = gobase.ParseDurationEx("reloadInterval", time.Second*60)

	varsConf := wrapper.CloneFrom(conf.ValueByName("vars"))
	this.reloadFrom()
	// 确保varsConf 覆盖from中的变量
	this.reloadVars(varsConf)
	if this.reloadInterval > 0 {
		gotask.DefaultPatrolTask().AddTask(this.PlugId, this.reloadInterval, func(id interface{}, args ...interface{}) {
			go gobase.GoRun(func() {
				this.reloadFrom()
				// 确保varsConf 覆盖from中的变量
				this.reloadVars(varsConf)
			})
		})
		this.PlgBase.AddCloseFunc("reloadInterval", func(args ...interface{}) {
			gotask.DefaultPatrolTask().DelTask(this.PlugId)
		})
	} else {
		this.PlgBase.RemoveAndCloseFunc("reloadInterval")
	}

	return nil
}

func (this *PlgVarsLoader) Close() (err error) {
	this.PlgBase.ExecuteAllAndClose()
	return
}

func CreatePlgVarsLoaderFunc(args ...interface{}) (rval interface{}, err error) {
	obj := &PlgVarsLoader{}

	if len(args) > 0 {
		if str, ok := args[0].(string); ok {
			obj.PlugId = str
		}
	}
	rval = obj
	return
}

func init() {
	factory.RegisterCreateFunc("plgs.vars", CreatePlgVarsLoaderFunc)
}
